from random import *
import numpy as np


def intercross(a, b):
    """
    部分映射,杂交2个个体
    :param a: 带交叉个体
    :param b: 同上
    :return: 交叉后个体
    """
    L = len(a)
    r1 = randint(1, L)  # 取值范围:[1,L]
    r2 = randint(1, L)
    if r1 != r2:
        s = min(r1, r2)
        e = max(r1, r2)
        for i in range(s - 1, e):
            a1, b1 = a.copy(), b.copy()
            # 交叉
            a[i], b[i] = b1[i], a1[i]
            # 找出与当前换了之后重复的点，并用本次循环替换前的值替换
            x = np.where(a == a[i])
            y = np.where(b == b[i])
            i1 = [x[0][j] for j in range(len(x[0])) if x[0][j] != i]
            i2 = [y[0][j] for j in range(len(y[0])) if y[0][j] != i]
            if len(i1) > 0:
                a[i1] = a1[i]
            if len(i2) > 0:
                b[i2] = b1[i]
    return [a, b]


def Recombin(Selch, Pc):
    """
    交叉操作，避免局部最优解，但也不利于子代继承亲代的较多信息，对亲代较优基因破坏很大
    :param Selch: 被选择的个体
    :param Pc: 交叉概率
    :return: 交叉后的个体
    """
    NSel = Selch.shape[0]  # 行数
    for i in range(0, NSel - NSel % 2, 2):
        if Pc >= random():
            [Selch[i, :], Selch[i + 1, :]] = intercross(Selch[i, :], Selch[i + 1, :])

    return Selch
